﻿Option Strict On

Imports System.IO
Imports System.Xml
Imports System.Linq
Imports System.Xml.Linq
'Imports <xmlns:mg="Matching Game">
'Imports <xmlns="Matching Games">

Public Class Gameset
    Private Const DefaultGameSetFile As String = "DefaultGameSet.xml"
    Private Const MinAsciiChar As Integer = 33
    Private Const MaxAsciiChar As Integer = 126

    Private pvGameCard As String
    Private pvGameCardType As String
    Private pvGameCardFont As System.Drawing.Font
    Private pvGameSetFile As String
    Private pvGameMessage As String

    Private pvListofGameNames As New List(Of String)
    Private pvListofGameIcons As New List(Of String)

    Private XDocGameSet As XDocument
    Private XDocGameCard As XElement

    Private pvIconCount As Integer = 8
    Private pvTextLowerChar As Integer = 33
    Private pvTextUpperChar As Integer = 126

    Structure CurrentGame
        Public Name As String
        Public Type As String
    End Structure

    Public Game As New CurrentGame


    Public Sub New()
        pvIconCount = IconSquareCount
    End Sub


    Public Property GameCard() As String
        Get
            'Return pvGameCard
            Return Game.Name
        End Get
        Set(ByVal value As String)
            pvGameCard = value
            Game.Name = value
        End Set
    End Property

    Public Property GameCardType() As String
        Get
            'Return pvGameCardType
            Return Game.Type
        End Get
        Set(ByVal value As String)
            pvGameCardType = value
            Game.Type = value
        End Set
    End Property

    Public Property GameCardFont() As System.Drawing.Font
        Get
            Return pvGameCardFont
        End Get
        Set(ByVal value As System.Drawing.Font)
            pvGameCardFont = value
        End Set
    End Property

    Public Property IconCount() As Integer
        Get
            Return pvIconCount
        End Get
        Set(ByVal value As Integer)
            pvIconCount = value
        End Set
    End Property


    Public Function GetListofIcons() As List(Of String)
        Return pvListofGameIcons
    End Function


    ''' <summary>
    ''' load specified gamecard, load default gamecard if not successful
    ''' creates list of icons, game name, game type, and font if text
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub LoadGameCard(ByVal Gamecard As String)
        Dim val As String
        Dim ErrMessage As String = ""
        Dim xmlGameCard As String
        Dim xmlGameType As String

        'process xml, search for gamecard
        Gamecard = Gamecard.ToUpper()
        For Each card As XElement In XDocGameSet.<gamecards>.<gamecard>
            Console.WriteLine(card)
            xmlGameCard = card.@name
            If xmlGameCard.ToUpper = Gamecard Then
                pvGameCard = xmlGameCard
                pvGameCardFont = Nothing
                pvListofGameIcons.Clear()
                xmlGameType = card.<gametype>.Value.ToLower
                'Stop
                Select Case xmlGameType
                    Case "text", "randomtext"
                        Dim fontname As String
                        Dim fontsize As Integer
                        Dim fontbold As Boolean
                        Dim fontitalic As Boolean
                        Dim fontstrike As Boolean
                        Dim fontunder As Boolean
                        fontname = card.<text>.<fontname>.Value
                        fontsize = CInt(card.<text>.<fontsize>.Value)
                        If card.<text>.<fontbold>.Value.ToLower = "Y" Then fontbold = True Else fontbold = False
                        If card.<text>.<fontitalic>.Value.ToLower = "Y" Then fontitalic = True Else fontitalic = False
                        If card.<text>.<fontstrike>.Value.ToLower = "Y" Then fontstrike = True Else fontstrike = False
                        If card.<text>.<fontunder>.Value.ToLower = "Y" Then fontunder = True Else fontunder = False

                        pvGameCardFont = CreateFont(fontName:=fontname, _
                                                    fontSize:=fontsize, _
                                                    isBold:=fontbold, _
                                                    isItalic:=fontitalic, _
                                                    isStrikeout:=fontstrike, _
                                                    isUnder:=fontunder)

                        Select Case xmlGameType
                            Case "text"
                                Dim textmembers As String = card.<text>.<members>.Value
                                If textmembers <> "" Then
                                    Do
                                        For Each icon In Split(textmembers, "|")
                                            'add twice
                                            pvListofGameIcons.Add(icon)
                                            pvListofGameIcons.Add(icon)
                                            If pvListofGameIcons.Count >= pvIconCount Then Exit For
                                        Next
                                    Loop Until pvListofGameIcons.Count >= pvIconCount
                                End If
                            Case "randomtext"

                                'verify lower range value is integer
                                Dim lowerascii As Integer = 0
                                val = card.<text>.<lowerrange>.Value
                                If Integer.TryParse(val, 0) Then lowerascii = CInt(val)

                                'verify upper range value is integer
                                Dim upperascii As Integer = 0
                                val = card.<text>.<upperrange>.Value
                                If Integer.TryParse(val, 0) Then upperascii = CInt(val)

                                'check range values
                                If lowerascii > MinAsciiChar AndAlso _
                                    upperascii > MinAsciiChar AndAlso _
                                    lowerascii < MaxAsciiChar AndAlso _
                                    upperascii < MaxAsciiChar AndAlso _
                                    (upperascii - lowerascii) > IconSquareCount Then
                                    Dim rand = New Random
                                    Do
                                        val = Chr(rand.Next(lowerascii, upperascii))
                                        If Not pvListofGameIcons.Contains(val) Then
                                            pvListofGameIcons.Add(val)
                                            pvListofGameIcons.Add(val)
                                        End If
                                    Loop Until pvListofGameIcons.Count >= pvIconCount
                                Else
                                    ErrMessage = ErrMessage & Chr(13) & "Invalid range."
                                End If

                            Case Else
                        End Select

                    Case "images", "randomimages"
                        Select Case xmlGameType
                            Case "images"
                                'get list of xml field values
                                For Each fn As String In From el In card.<images>.<image> Select el.Value
                                    If fn <> "" Then
                                        pvListofGameIcons.Add(fn)
                                        pvListofGameIcons.Add(fn)
                                    End If
                                    If pvListofGameIcons.Count >= pvIconCount Then Exit For
                                Next

                                If pvListofGameIcons.Count = 0 Then
                                    'if none, set error message
                                    ErrMessage = ErrMessage & Chr(13) & "No images specified in game definition."
                                ElseIf pvListofGameIcons.Count < IconCount Then
                                    'if less than needed, duplicate existing items as necessary
                                    Do
                                        For intX As Integer = 0 To pvListofGameIcons.Count - 1
                                            pvListofGameIcons.Add(pvListofGameIcons(intX))
                                            pvListofGameIcons.Add(pvListofGameIcons(intX))
                                            If pvListofGameIcons.Count >= pvIconCount Then Exit For
                                        Next
                                    Loop Until pvListofGameIcons.Count >= pvIconCount
                                End If
                                Stop

                            Case "randomimages"
                                Dim folder As String = card.<images>.<folder>.Value
                                Stop
                                If Directory.Exists(folder) Then
                                    'Dim ext = {"*.jpg", "*.bmp", "*png"}
                                    Dim ext = Split("*.jpg,*.bmp,*png", ",")
                                    pvListofGameIcons = ext.SelectMany(Function(f) Directory.GetFiles(folder, f)).ToList
                                    Stop

                                    If pvListofGameIcons.Count = 0 Then
                                        'if none, set error message
                                        ErrMessage = ErrMessage & Chr(13) & "No images found in specified folder."
                                    ElseIf pvListofGameIcons.Count < IconCount Then
                                        'if less than needed, duplicate existing items as necessary
                                        Do
                                            For intX As Integer = 0 To pvListofGameIcons.Count - 1
                                                pvListofGameIcons.Add(pvListofGameIcons(intX))
                                                pvListofGameIcons.Add(pvListofGameIcons(intX))
                                                If pvListofGameIcons.Count >= pvIconCount Then Exit For
                                            Next
                                        Loop Until pvListofGameIcons.Count >= pvIconCount
                                    End If

                                Else
                                    Console.WriteLine("{0} is not a valid file or directory.", folder)
                                End If
                        End Select

                    Case Else
                        ErrMessage = "Unknown game type."
                End Select

                val = String.Join(",", pvListofGameIcons)
                Debug.Print("Errs = " & ErrMessage)
                Debug.Print("Type = " & xmlGameType)
                Debug.Print("Count = " & pvListofGameIcons.Count)
                Debug.Print("List = " & val)
                Stop

                pvGameCardType = xmlGameType
                Exit Sub
            End If
        Next

    End Sub


    Public Sub SaveGameCard(ByVal myFont As System.Drawing.Font)
        'Dim fntname As String
        Try
            pvGameCardFont = CType(My.Settings.Item("Font" & pvGameCard), System.Drawing.Font)
        Catch ex As Exception
            Dim GameCardFont As New System.Drawing.Font("Webdings", 72, FontStyle.Bold)
            AddProperty("Font" & pvGameCard, "", GetType(System.Drawing.Font))
            My.MySettings.Default.Reload()
            My.MySettings.Default.Item("Font" & pvGameCard) = CType(pvGameCardFont, System.Drawing.Font)
        End Try
        pvGameCardFont = CType(My.Settings.Item("Font" & GameCard), System.Drawing.Font)
        Stop

        pvGameCardFont = CreateFont(fontName:=GameCardFont.Name, fontSize:=48, isBold:=GameCardFont.Bold, isItalic:=GameCardFont.Italic, isStrikeout:=False, isUnder:=False)
        Dim fntsize = pvGameCardFont.Size

    End Sub


    Public Function CreateFont(ByVal fontName As String, _
                               ByVal fontSize As Integer, _
                               ByVal isBold As Boolean, _
                               ByVal isItalic As Boolean, _
                               ByVal isStrikeout As Boolean, _
                               ByVal isUnder As Boolean) As System.Drawing.Font

        Dim styles As FontStyle = FontStyle.Regular

        If (isBold) Then
            styles = styles Or FontStyle.Bold
        End If

        If (isItalic) Then
            styles = styles Or FontStyle.Italic
        End If

        If (isStrikeout) Then
            styles = styles Or FontStyle.Strikeout
        End If

        Dim newFont As New System.Drawing.Font(fontName, fontSize, styles)
        Return newFont

    End Function



    ''' <summary>
    ''' load specified gameset, create default gameset if not successful
    ''' </summary>
    ''' <remarks></remarks>
    Public Function LoadGameSet(ByVal GameSetFile As String) As XDocument
        Dim xmlGameCard As String

        Try
            XDocGameSet = XDocument.Load(GameSetFile)
        Catch ex As Exception
            Console.WriteLine(ex)
            If System.IO.File.Exists(GameSetFile) Then
                MsgBox("GameSet file " & GameSetFile & " invalid. Loading defaults.")
            Else
                MsgBox("GameSet file " & GameSetFile & " not found. Loading defaults.")
            End If
            XDocGameSet = CreateDefaultGameSet()
            Stop
            Call ExportGameSet(GameSetFile)
        End Try

        pvGameCard = ""
        pvListofGameNames.Clear()
        For Each el As XElement In XDocGameSet.<gamecards>.<gamecard>
            Console.WriteLine(el)
            xmlGameCard = el.@name
            pvListofGameNames.Add(xmlGameCard)
            'set first game as default (can be overridden by game settings)
            If pvGameCard = "" Then pvGameCard = xmlGameCard
        Next

        Return XDocGameSet
    End Function


    ''' <summary>
    ''' create default gameset
    ''' </summary>
    ''' <remarks></remarks>
    Public Function CreateDefaultGameSet() As XDocument
        Dim XDocGameSet As XDocument

        XDocGameSet = _
    <?xml version="1.0" encoding="utf-8" standalone="yes"?>
    <!--This is a comment-->
    <gamecards>
        <gamecard name="Webding">
            <gamesize>16</gamesize>
            <gametype>Text</gametype>
            <text>
                <fontname>Webding</fontname>
                <fontsize>72</fontsize>
                <fontbold>Y</fontbold>
                <fontitalic>N</fontitalic>
                <fontstrike>N</fontstrike>
                <fontunder>N</fontunder>
                <range></range>
                <members>!|N|,|k|b|v|w|z</members>
            </text>
            <images>
                <folder></folder>
                <image></image>
                <image></image>
                <image></image>
                <image></image>
                <image></image>
                <image></image>
                <image></image>
                <image></image>
            </images>
        </gamecard>
    </gamecards>

        Return XDocGameSet
    End Function


    ''' <summary>
    ''' get gameset file
    ''' </summary>
    ''' <remarks></remarks>
    Public Function GetGameSetFile(ByVal GameSetFile As String) As String
        Dim openFileDialog1 As New OpenFileDialog()

        'Set file dialog properties
        openFileDialog1.Title = "Select a gameset file to import"
        openFileDialog1.Filter = "XML|*.xml"
        openFileDialog1.FilterIndex = 2
        openFileDialog1.DefaultExt = "XML"
        openFileDialog1.Multiselect = False
        openFileDialog1.FileName = pvGameSetFile
        openFileDialog1.InitialDirectory = ""

        'Show file dialog
        If openFileDialog1.ShowDialog() = DialogResult.OK Then
            pvGameSetFile = openFileDialog1.FileName
        End If

        Return pvGameSetFile

    End Function


    ''' <summary>
    ''' import gameset from file
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub ImportGameSet(ByVal Filename As String)
        Dim XDocGameSet As XDocument
        'Dim qxElement As IEnumerable(Of XElement)
        Dim GameName As String

        If Not System.IO.File.Exists(Filename) Then
            Filename = GetGameSetFile(Filename)
        End If

        Try
            XDocGameSet = LoadGameSet(Filename)
            Stop
            Console.WriteLine("Number of gamecards = " & XDocGameSet.<gamecards>.<gamecard>.Count())
        Catch ex As Exception
            Console.Write(ex)
            Stop
            Exit Sub
        End Try

        'process elements of imported xml, check for duplicates
        For Each el As XElement In XDocGameSet.<gamecards>
            Console.WriteLine(el)
            GameName = el.@name
            Stop
        Next

        Call ExportGameSet(AppDir & "exp_" & GameSetFile)

    End Sub


    ''' <summary>
    ''' export gameset to file
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub ExportGameSet(ByVal Filename As String)
        Dim sw = New StringWriter()

        'save to XmlWriter
        Dim settings = New XmlWriterSettings()
        settings.Indent = True

        Dim writer = XmlWriter.Create(sw, settings)
        Try
            XDocGameSet.Save(writer)
        Catch ex As Exception
            Console.WriteLine(ex)
            Stop
        End Try
        writer.Close()

        'save to file
        XDocGameSet.Save(Filename)
        Console.WriteLine(XDocGameSet)
        Stop

    End Sub


    Public Sub AddGameCard()

    End Sub

    Public Sub DeleteGameCard()

    End Sub

    ''' <summary>
    ''' return list of games
    ''' </summary>
    ''' <remarks></remarks>
    Public Function GetGameNames() As List(Of String)
        Return pvListofGameNames
    End Function



    Public Sub XLinq1()
        Dim XDoc As XDocument
        Dim XEle As XElement
        Dim XGameCard As XElement
        Dim qxElement As IEnumerable(Of XElement)
        Dim qxString As IEnumerable(Of String)

        XDocGameSet = LoadGameSet(AppDir & GameSetFile)

        If System.IO.File.Exists(AppDir & GameSetFile) Then
            XDocGameSet = XDocument.Load(AppDir & GameSetFile)
            Dim XDocTest = XDocument.Load(AppDir & "x" & GameSetFile)

            XDoc = XDocument.Load(AppDir & GameSetFile)
            XEle = XElement.Load(AppDir & GameSetFile)

            Console.WriteLine("Name of root element is " & XDocGameSet.Root.Name.ToString)

            'getting elements from xdocument
            qxElement = _
                    From el In XDocGameSet.Elements() _
                    Select el
            Console.WriteLine("Number of elements using XDocument.Load is " & qxElement.Count)

            'getting elements from xelement
            qxElement = _
                    From el In XEle.Elements() _
                    Select el
            Console.WriteLine("Number of elements using XElement.Load is " & qxElement.Count)


            'getting specified elements
            qxElement = XDocGameSet.<gamecards>.<gamecard>
            Console.WriteLine("Number of gamecards = " & qxElement.Count())

            'getting list of element values only
            qxString = _
                From el In XDocGameSet.<gamecards>.<gamecard> _
                Select el.@name
            Console.WriteLine("Number of names = " & qxString.Count())
            For Each el As String In qxString
                Console.WriteLine(el)
            Next

            'getting elements of specified attribute value
            qxElement = _
                From el In XDocGameSet.<gamecards>.<gamecard> _
                Where el.@name = "Webding" _
                Select el
            Console.WriteLine("Number of gamecards named Webding = " & qxElement.Count())
            For Each el As XElement In qxElement
                'Console.WriteLine(el)
                XGameCard = el
                'XDocTest.Root.Add(XGameCard.Nodes())
            Next

            'getting elements of specified element value
            qxElement = _
                From el In XDocGameSet.<gamecards>.<gamecard> _
                Where el.<gametype>.Value = "Images" _
                Select el
            Console.WriteLine("Number of gamecards of type Images = " & qxElement.Count())
            For Each el As XElement In qxElement
                'Console.WriteLine(el)
                XGameCard = el
                XDocTest.Root.Add(XGameCard)
            Next
            Console.WriteLine(XDocTest)
            Stop

            Dim sw = New StringWriter()

            'save to XmlWriter
            Dim settings = New XmlWriterSettings()
            settings.Indent = True

            Dim writer = XmlWriter.Create(sw, settings)
            XDocTest.Save(writer)
            writer.Close()

            'save to file
            XDocTest.Save(AppDir & "x" & GameSetFile)
            Stop
        End If
        Stop

    End Sub


    ''' <summary>
    ''' Assign each icon from the list of icons to a random square
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub AssignIconsToSquares(ByVal ListofIconLabels As List(Of System.Windows.Forms.Label), ByVal ShowIcons As Boolean)
        Dim iconcolor As Color
        Dim ListofInt As New List(Of Integer)
        ListofInt = RandomIndex(ListofIconLabels.Count)

        If ShowIcons Then
            iconcolor = IconForeColor
        Else
            iconcolor = IconBackColor
        End If

        ' make it a list
        'Dim GameCardArray() As String = GameCardString.Split(CChar(StringDelimiter))
        'Dim icons As List(Of String) = GameCardArray.ToList()

        ' labels with Tag=icon are assigned an icon
        For Each iconLabel In ListofIconLabels
            iconLabel.ForeColor = iconcolor
            iconLabel.Enabled = True

            Select Case pvGameCardType
                Case "text", "randomtext"
                    iconLabel.Text = pvListofGameIcons(1)
                    Select Case pvGameCardType
                        Case "text"
                        Case "randomtext"
                    End Select

                Case "images", "randomimages"
                    'img1 = System.Drawing.Image.FromFile(AppDir & "my photo.jpg")
                    'img1.Size = iconLabel.Size
                    'iconLabel.BackgroundImageLayout = ImageLayout.Stretch
                    'iconLabel.BackgroundImage = img
                    'iconLabel.BackgroundImage = Nothing
                    'iconLabel.Image = img2
                    'iconLabel.Image = Nothing
                    Select Case pvGameCardType
                        Case "images"
                        Case "randomimages"
                    End Select
                Case Else
            End Select

        Next

    End Sub


    ''' <summary>
    ''' Assign color background to icon squares
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub AssignColorsToSquares(ByVal ListofIconLabels As List(Of System.Windows.Forms.Label))

        Dim brightness As Single
        brightness = IconBackColor.GetBrightness
        If brightness < 0.5 Then
            IconForeColor = Color.White
        Else
            IconForeColor = Color.Black
        End If

        ' labels with Tag=icon are assigned an icon
        For Each iconLabel In ListofIconLabels
            iconLabel.ForeColor = IconForeColor
            iconLabel.BackColor = IconBackColor
            'iconLabel.Enabled = True
        Next

    End Sub


    ''' <summary>
    ''' Show icons and disable icon squares
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub ShowIcons(ByVal ListofIconLabels As List(Of System.Windows.Forms.Label))
        Dim val As String

        For Each iconLabel In ListofIconLabels
            iconLabel.Visible = True
            iconLabel.Enabled = False
            Select Case "x" & pvGameCardType
                Case "text", "randomtext"
                    'iconLabel.ForeColor = IconForeColor
                    iconLabel.Visible = True
                    iconLabel.Enabled = False

                Case "images", "randomimages"
                    val = CStr(iconLabel.Tag)
                    val = Mid(val, 4)
                    Dim img2 = System.Drawing.Image.FromFile(val)
                    Stop
                    iconLabel.BackgroundImageLayout = ImageLayout.Stretch
                    iconLabel.BackgroundImage = Nothing
                    iconLabel.Image = img2
                Case Else
            End Select
        Next

    End Sub

    ''' <summary>
    ''' Show icons and disable icon squares
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub SetIconSquares(ByVal ListofIconLabels As List(Of System.Windows.Forms.Label), ByVal ShowIcons As Boolean, ByVal EnableIcons As Boolean)

        For Each iconLabel In ListofIconLabels
            iconLabel.Visible = ShowIcons
            iconLabel.Enabled = EnableIcons
        Next

    End Sub


End Class
